package com.longcai.cm.web.controller;

import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.longcai.cm.base.aop.Log;
import com.longcai.cm.bean.R;
import com.longcai.cm.common.utils.aes.AesUtil;
import com.longcai.cm.moudules.system.bean.MenuTreeBean;
import com.longcai.cm.moudules.system.domain.SysMenus;
import com.longcai.cm.moudules.system.domain.SysRoleMenus;
import com.longcai.cm.moudules.system.service.SysMenusService;
import com.longcai.cm.moudules.system.service.SysRoleMenusService;
import com.longcai.cm.moudules.system.service.SysUsersService;
import com.longcai.cm.moudules.system.utils.PasswordHelper;
import com.longcai.cm.moudules.system.utils.ShiroUtils;
import io.swagger.annotations.Api;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * 用户管理
 *
 * @author chenyue
 */
@RestController
@Api(value = "个人中心-登录", tags = "个人中心-登录")
@ApiSort(0)
public class LoginController {

    @Resource
    private SysUsersService sysUsersService;

    @Resource
    private SysMenusService sysMenusService;

    @Resource
    private SysRoleMenusService sysRoleMenusService;

    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;

    @GetMapping(value = "/getCodeImage")
    public R<String> getCodeImage(HttpServletRequest request, HttpServletResponse response) {

        String imageStr = "";
        try {
            HttpSession session = request.getSession();
            response.setDateHeader("Expires", 0);
            response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
            response.addHeader("Cache-Control", "post-check=0, pre-check=0");
            response.setHeader("Pragma", "no-cache");
            response.setContentType("image/jpeg");

            String type = request.getParameter("type"); // math 、 char
            type = "math";
            String capStr = null;
            String code = null;
            BufferedImage bi = null;
            if ("math".equals(type)) {
                String capText = captchaProducerMath.createText();
                capStr = capText.substring(0, capText.lastIndexOf("@"));
                code = capText.substring(capText.lastIndexOf("@") + 1);
                bi = captchaProducerMath.createImage(capStr);
            } else if ("char".equals(type)) {
                capStr = code = captchaProducer.createText();
                bi = captchaProducer.createImage(capStr);
            }
            session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code);

            imageStr = bufferedImageToBase64(bi);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success(imageStr);
    }


    private static String bufferedImageToBase64(BufferedImage bufferedImage) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
        try {
            ImageIO.write(bufferedImage, "png", baos);//写入流中
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = baos.toByteArray();//转换成字节
        byte[] encode = Base64.getEncoder().encode(bytes);//转换成base64串
        String pngBase64String = new String(encode).trim();
        pngBase64String = pngBase64String.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
        return "data:image/jpg;base64," + pngBase64String;
    }


    @PostMapping(value = "/checkCode")
    public R checkCode(HttpServletRequest request) {

        String code = request.getParameter("code");
        HttpSession session = request.getSession();
        Object sessionCode = session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if (sessionCode == null) {
            return R.error("验证码已失效");
        }
        if (code.equals(sessionCode.toString())) {
            return R.success();
        } else {
            return R.error("验证码错误");
        }
    }

    /**
     * @param request [请求信息]
     * @return R
     */
    @PostMapping(value = "/login")
    @Log(value = "用户登录", type = "1")
    public R login(HttpServletRequest request) {
        String s = request.getParameter("username");
        String userName = AesUtil.decodeToStr(s);
        String ss = request.getParameter("password");
        String passWord = AesUtil.decodeToStr(ss);
        String code = request.getParameter("code");
        HttpSession session = request.getSession();
        Object sessionCode = session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if (sessionCode == null) {
            return R.error("验证码已失效");
        }
        if (code.equals(sessionCode.toString())) {
            String encryptPassword = PasswordHelper.encryptPassword(passWord);
            Subject subject = SecurityUtils.getSubject();
            AuthenticationToken token;
            // 获取用户类型
            System.out.println("管理员用户登录");
            token = new UsernamePasswordToken(userName, encryptPassword, false);
            try {
                subject.login(token);
            } catch (LockedAccountException lae) {
                lae.printStackTrace();
                return R.error("用户已经被锁定不能登录，请与管理员联系！");
            } catch (AuthenticationException e) {
                e.printStackTrace();
                return R.error("用户或密码不正确！");
            } catch (Exception e) {
                e.printStackTrace();
                return R.error("后台服务异常！");
            }
            // 获取用户角色信息
            String roleId = sysUsersService.getRoleIdByUserId(ShiroUtils.getUserId());

            Map<String, Object> resultMap = new HashMap<String, Object>();
            resultMap.put("roleId", roleId);
            resultMap.put("access_token", subject.getSession().getId().toString());

            return R.success(resultMap);
        } else {
            return R.error("验证码错误");
        }

    }


    /**
     * @param request  [请求信息]
     * @param response [响应信息]
     * @return R
     */
    @Log("获取登录信息")
    @PostMapping(value = "/getUserInfo")
    public R<Map<String, Object>> getUserInfo(HttpServletRequest request, HttpServletResponse response) {

        Object principal = SecurityUtils.getSubject().getPrincipal();
        if (principal == null) {
            return R.error(401, "会话过期");
        }
        Map<String, Object> userMap = (Map<String, Object>) principal;
        String userType = userMap.get("userType").toString();
        String userId = ShiroUtils.getUserId();
        String roleId;
        List<SysRoleMenus> roleMenuList;
        roleId = sysUsersService.getRoleIdByUserId(userId);
        roleMenuList = sysUsersService.getRoleMenuListByUserId(userId);
        // 该用户对应的菜单权限
        userMap.put("menuList", sysMenusService.getMenuMeanListByUserId(userId));
        userMap.put("remark", roleId);
        userMap.put("roleId", roleId);
        userMap.put("userId", ShiroUtils.getUserId());
        userMap.put("userType", userType);
        List<String> idList = new ArrayList<>();
        for (SysRoleMenus roleMenus : roleMenuList) {
            idList.add(roleMenus.getMenuCode());
        }
        userMap.put("menuCodes", idList);
        return R.success(userMap);


    }

    private List<MenuTreeBean> getChild(String id, List<SysMenus> allMenu, List<String> checkedlist) {
        // 子菜单
        List<MenuTreeBean> childList = new ArrayList<MenuTreeBean>();

        // 遍历所有节点，将所有菜单的父id与传过来的根节点的id比较
        for (SysMenus systemMenu : allMenu) {
            if (checkedlist.contains(systemMenu.getId()) || checkedlist.size() < 1) {
                // 相等说明：为该根节点的子节点。
                if (systemMenu.getPid() != null && (systemMenu.getPid().equals(id))) {
                    MenuTreeBean a = new MenuTreeBean(systemMenu);
                    a.setPid(systemMenu.getPid());
                    childList.add(a);
                }
            }
        }
        // 递归
        for (MenuTreeBean nav : childList) {
            nav.setChildren(getChild(nav.getId(), allMenu, checkedlist));
        }
        // 如果节点下没有子节点，返回一个空List（递归退出）
        if (childList.size() == 0) {
            return new ArrayList<MenuTreeBean>();
        }
        return childList;
    }

    /**
     * 【API】  ---- 注销登录
     *
     * @param request  [请求信息]
     * @param response [响应信息]
     * @return R
     */
    @Log(value = "用户注销", type = "1")
    @PostMapping(value = "/logOut")
    public R logOut(HttpServletRequest request, HttpServletResponse response) {
        Subject subject = SecurityUtils.getSubject();
        // 注销
        subject.logout();
        return R.success("退出成功");
    }


    public static void main(String[] args) {

        String s = PasswordHelper.encryptPassword("admin");
        System.out.println("密码加密结果:" + s);
    }


}
